home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / bash_114.zip / bash-1.14.2 / test.c < prev    next >
C/C++ Source or Header  |  1994-08-10  |  26KB  |  1,131 lines

  1. /* GNU test program (ksb and mjb) */
  2.  
  3. /* Modified to run with the GNU shell Apr 25, 1988 by bfox. */
  4.  
  5. /* Copyright (C) 1987, 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
  6.  
  7.    This file is part of GNU Bash, the Bourne Again SHell.
  8.  
  9.    Bash is free software; you can redistribute it and/or modify it under
  10.    the terms of the GNU General Public License as published by the Free
  11.    Software Foundation; either version 2, or (at your option) any later
  12.    version.
  13.  
  14.    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  15.    WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16.    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17.    for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License along
  20.    with Bash; see the file COPYING.  If not, write to the Free Software
  21.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  22.  
  23. /* Define STANDALONE to get the /bin/test version.  Otherwise, you get 
  24.    the shell builtin version. */
  25. /* #define STANDALONE */
  26.  
  27. #include <stdio.h>
  28. #include "bashtypes.h"
  29.  
  30. #if !defined (STANDALONE)
  31. #  if !defined (_POSIX_VERSION)
  32. #    include <sys/file.h>
  33. #  endif /* !_POSIX_VERSION */
  34. #  include "posixstat.h"
  35. #  include "filecntl.h"
  36. #  include "shell.h"
  37. #else /* STANDALONE */
  38. #  include "system.h"
  39. #  if !defined (S_IXUGO)
  40. #    define S_IXUGO 0111
  41. #  endif
  42. #  if defined (HAVE_UNISTD_H)
  43. #    include <unistd.h>
  44. #  endif /* HAVE_UNISTD_H */
  45. #  define whitespace(c) (((c) == ' ') || ((c) == '\t'))
  46. #  define digit(c)  ((c) >= '0' && (c) <= '9')
  47. #  define digit_value(c) ((c) - '0')
  48. #endif /* STANDALONE */
  49.  
  50. #if !defined (STRLEN)
  51. #  define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
  52. #endif
  53.  
  54. #include <errno.h>
  55. #if !defined (errno)
  56. extern int errno;
  57. #endif /* !errno */
  58.  
  59. #if !defined (STREQ)
  60. #  define STREQ(a, b) ((a)[0] == (b)[0] && strcmp (a, b) == 0)
  61. #endif /* !STREQ */
  62.  
  63. #if !defined (member)
  64. #  define member(c, s) (int)((c) ? (char *)strchr ((s), (c)) : 0)
  65. #endif /* !member */
  66.  
  67. /* Make gid_t and uid_t mean something for non-posix systems. */
  68. #if !defined (_POSIX_VERSION) && !defined (HAVE_UID_T)
  69. #  if !defined (gid_t)
  70. #    define gid_t int
  71. #  endif
  72. #  if !defined (uid_t)
  73. #    define uid_t int
  74. #  endif
  75. #endif /* !_POSIX_VERSION */
  76.  
  77. /* What type are the user and group ids?  GID_T is actually the type of
  78.    the members of the array that getgroups(3) fills in from its second
  79.    argument. */
  80. #if defined (INT_GROUPS_ARRAY)
  81. #  define GID_T int
  82. #  define UID_T int
  83. #else /* !INT_GROUPS_ARRAY */
  84. #  define GID_T gid_t
  85. #  define UID_T uid_t
  86. #endif /* !INT_GROUPS_ARRAY */
  87.  
  88. #if !defined (Linux) && !defined (USGr4_2) && !defined (SunOS5)
  89. extern gid_t getegid ();
  90. extern uid_t geteuid ();
  91. #  if !defined (sony)
  92. extern gid_t getgid ();
  93. #  endif /* !sony */
  94. #endif /* !Linux && !USGr4_2 && !SunOS5 */
  95.  
  96. #if !defined (R_OK)
  97. #define R_OK 4
  98. #define W_OK 2
  99. #define X_OK 1
  100. #define F_OK 0
  101. #endif /* R_OK */
  102.  
  103. /* The following few defines control the truth and false output of each stage.
  104.    TRUE and FALSE are what we use to compute the final output value.
  105.    SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
  106.    TRUTH_OR is how to do logical or with TRUE and FALSE.
  107.    TRUTH_AND is how to do logical and with TRUE and FALSE..
  108.    Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b,
  109.     SHELL_BOOLEAN = (!value). */
  110. #define TRUE 1
  111. #define FALSE 0
  112. #define SHELL_BOOLEAN(value) (!(value))
  113. #define TRUTH_OR(a, b) ((a) | (b))
  114. #define TRUTH_AND(a, b) ((a) & (b))
  115.  
  116. #if defined (STANDALONE)
  117. #  define test_exit(val) exit (val)
  118. #else
  119.    static jmp_buf test_exit_buf;
  120.    static int test_error_return = 0;
  121. #  define test_exit(val) \
  122.     do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0)
  123. #endif /* STANDALONE */
  124.  
  125. #if defined (AFS)
  126.   /* We have to use access(2) for machines running AFS, because it's
  127.      not a Unix file system.  This may produce incorrect answers for
  128.      non-AFS files.  I hate AFS. */
  129. #  define EACCESS(path, mode)    access(path, mode)
  130. #else
  131. #  define EACCESS(path, mode)    eaccess(path, mode)
  132. #endif /* AFS */
  133.  
  134. static int pos;        /* The offset of the current argument in ARGV. */
  135. static int argc;    /* The number of arguments present in ARGV. */
  136. static char **argv;    /* The argument list. */
  137. static int noeval;
  138.  
  139. static int isint ();
  140. static int unop ();
  141. static int binop ();
  142. static int unary_operator ();
  143. static int binary_operator ();
  144. static int two_arguments ();
  145. static int three_arguments ();
  146. static int posixtest ();
  147.  
  148. static int expr ();
  149. static int term ();
  150. static int and ();
  151. static int or ();
  152.  
  153. static void
  154. test_syntax_error (format, arg)
  155.      char *format, *arg;
  156. {
  157. #if !defined (STANDALONE)
  158.   extern int interactive_shell;
  159.   extern char *get_name_for_error ();
  160.   if (!interactive_shell)
  161.     fprintf (stderr, "%s: ", get_name_for_error ());
  162. #endif
  163.   fprintf (stderr, "%s: ", argv[0]);
  164.   fprintf (stderr, format, arg);
  165.   fflush (stderr);
  166.   test_exit (SHELL_BOOLEAN (FALSE));
  167. }
  168.  
  169. /* A wrapper for stat () which disallows pathnames that are empty strings
  170.    and handles /dev/fd emulation on systems that don't have it. */
  171. static int
  172. test_stat (path, finfo)
  173.      char *path;
  174.      struct stat *finfo;
  175. {
  176.   if (*path == '\0')
  177.     {
  178.       errno = ENOENT;
  179.       return (-1);
  180.     }
  181. #if !defined (HAVE_DEV_FD)
  182.   if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
  183.     {
  184.       int fd;
  185.       if (isint (path + 8, &fd))
  186.     return (fstat (fd, finfo));
  187.       else
  188.     {
  189.       errno = EBADF;
  190.       return (-1);
  191.     }
  192.     }
  193. #endif /* !HAVE_DEV_FD */
  194.   return (stat (path, finfo));
  195. }
  196.  
  197. /* Do the same thing access(2) does, but use the effective uid and gid,
  198.    and don't make the mistake of telling root that any file is
  199.    executable. */
  200. static int
  201. eaccess (path, mode)
  202.      char *path;
  203.      int mode;
  204. {
  205.   struct stat st;
  206.   static int euid = -1;
  207.  
  208.   if (test_stat (path, &st) < 0)
  209.     return (-1);
  210.  
  211.   if (euid == -1)
  212. #if defined (SHELL)
  213.     euid = current_user.euid;
  214. #else
  215.     euid = geteuid ();
  216. #endif
  217.  
  218.   if (euid == 0)
  219.     {
  220.       /* Root can read or write any file. */
  221.       if (mode != X_OK)
  222.     return (0);
  223.  
  224.       /* Root can execute any file that has any one of the execute
  225.      bits set. */
  226.       if (st.st_mode & S_IXUGO)
  227.     return (0);
  228.     }
  229.  
  230.   if (st.st_uid == euid)        /* owner */
  231.     mode <<= 6;
  232.   else if (group_member (st.st_gid))
  233.     mode <<= 3;
  234.  
  235.   if (st.st_mode & mode)
  236.     return (0);
  237.  
  238.   return (-1);
  239. }
  240.  
  241. #if defined (HAVE_GETGROUPS)
  242. /* The number of groups that this user is a member of. */
  243. static int ngroups = 0;
  244. static GID_T *group_array = (GID_T *)NULL;
  245. static int default_group_array_size = 0;
  246. #endif /* HAVE_GETGROUPS */
  247.  
  248. #if !defined (NOGROUP)
  249. #  define NOGROUP (GID_T) -1
  250. #endif
  251.  
  252. /* Return non-zero if GID is one that we have in our groups list. */
  253. int
  254. group_member (gid)
  255.      GID_T gid;
  256. {
  257.   static GID_T pgid = (GID_T)NOGROUP;
  258.   static GID_T egid = (GID_T)NOGROUP;
  259.  
  260.   if (pgid == (GID_T)NOGROUP)
  261. #if defined (SHELL)
  262.     pgid = (GID_T) current_user.gid;
  263. #else /* !SHELL */
  264.     pgid = (GID_T) getgid ();
  265. #endif /* !SHELL */
  266.  
  267.   if (egid == (GID_T)NOGROUP)
  268. #if defined (SHELL)
  269.     egid = (GID_T) current_user.egid;
  270. #else /* !SHELL */
  271.     egid = (GID_T) getegid ();
  272. #endif /* !SHELL */
  273.  
  274.   if (gid == pgid || gid == egid)
  275.     return (1);
  276.  
  277. #if defined (HAVE_GETGROUPS)
  278.   /* getgroups () returns the number of elements that it was able to
  279.      place into the array.  We simply continue to call getgroups ()
  280.      until the number of elements placed into the array is smaller than
  281.      the physical size of the array. */
  282.  
  283.   while (ngroups == default_group_array_size)
  284.     {
  285.       default_group_array_size += 64;
  286.  
  287.       group_array = (GID_T *)
  288.     xrealloc (group_array, default_group_array_size * sizeof (GID_T));
  289.  
  290.       ngroups = getgroups (default_group_array_size, group_array);
  291.     }
  292.  
  293.   /* In case of error, the user loses. */
  294.   if (ngroups < 0)
  295.     return (0);
  296.  
  297.   /* Search through the list looking for GID. */
  298.   {
  299.     register int i;
  300.  
  301.     for (i = 0; i < ngroups; i++)
  302.       if (gid == group_array[i])
  303.     return (1);
  304.   }
  305. #endif /* HAVE_GETGROUPS */
  306.  
  307.   return (0);
  308. }
  309.  
  310. /* Increment our position in the argument list.  Check that we're not
  311.    past the end of the argument list.  This check is supressed if the
  312.    argument is FALSE.  Made a macro for efficiency. */
  313. #if !defined (lint)
  314. #define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0)
  315. #endif
  316.  
  317. #if !defined (advance)
  318. static int
  319. advance (f)
  320.      int f;
  321. {
  322.   ++pos;
  323.  
  324.   if (f && pos >= argc)
  325.     beyond ();
  326. }
  327. #endif /* advance */
  328.  
  329. #define unary_advance() do { advance (1); ++pos; } while (0)
  330.  
  331. /*
  332.  * beyond - call when we're beyond the end of the argument list (an
  333.  *    error condition)
  334.  */
  335. static int
  336. beyond ()
  337. {
  338.   test_syntax_error ("argument expected\n", (char *)NULL);
  339. }
  340.  
  341. /* Syntax error for when an integer argument was expected, but
  342.    something else was found. */
  343. static void
  344. integer_expected_error (pch)
  345.      char *pch;
  346. {
  347.   test_syntax_error ("integer expression expected %s\n", pch);
  348. }
  349.  
  350. /* Return non-zero if the characters pointed to by STRING constitute a
  351.    valid number.  Stuff the converted number into RESULT if RESULT is
  352.    a non-null pointer to a long. */
  353. static int
  354. isint (string, result)
  355.      register char *string;
  356.      long *result;
  357. {
  358.   int sign;
  359.   long value;
  360.  
  361.   sign = 1;
  362.   value = 0;
  363.  
  364.   if (result)
  365.     *result = 0;
  366.  
  367.   /* Skip leading whitespace characters. */
  368.   while (whitespace (*string))
  369.     string++;
  370.  
  371.   if (!*string)
  372.     return (0);
  373.  
  374.   /* We allow leading `-' or `+'. */
  375.   if (*string == '-' || *string == '+')
  376.     {
  377.       if (!digit (string[1]))
  378.     return (0);
  379.  
  380.       if (*string == '-')
  381.     sign = -1;
  382.  
  383.       string++;
  384.     }
  385.  
  386.   while (digit (*string))
  387.     {
  388.       if (result)
  389.     value = (value * 10) + digit_value (*string);
  390.       string++;
  391.     }
  392.  
  393.   /* Skip trailing whitespace, if any. */
  394.   while (whitespace (*string))
  395.     string++;
  396.  
  397.   /* Error if not at end of string. */
  398.   if (*string)
  399.     return (0);
  400.  
  401.   if (result)
  402.     {
  403.       value *= sign;
  404.       *result = value;
  405.     }
  406.  
  407.   return (1);
  408. }
  409.  
  410. /* Find the modification time of FILE, and stuff it into AGE, a pointer
  411.    to a long.  Return non-zero if successful, else zero. */
  412. static int
  413. age_of (filename, age)
  414.      char *filename;
  415.      long *age;
  416. {
  417.   struct stat finfo;
  418.  
  419.   if (test_stat (filename, &finfo) < 0)
  420.     return (0);
  421.  
  422.   if (age)
  423.     *age = finfo.st_mtime;
  424.  
  425.   return (1);
  426. }
  427.  
  428. /*
  429.  * term - parse a term and return 1 or 0 depending on whether the term
  430.  *    evaluates to true or false, respectively.
  431.  *
  432.  * term ::=
  433.  *    '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename
  434.  *    '-'('L'|'x') filename
  435.  *     '-t' [ int ]
  436.  *    '-'('z'|'n') string
  437.  *    string
  438.  *    string ('!='|'=') string
  439.  *    <int> '-'(eq|ne|le|lt|ge|gt) <int>
  440.  *    file '-'(nt|ot|ef) file
  441.  *    '(' <expr> ')'
  442.  * int ::=
  443.  *    '-l' string
  444.  *    positive and negative integers
  445.  */
  446. static int
  447. term ()
  448. {
  449.   int value;
  450.  
  451.   if (pos >= argc)
  452.     beyond ();
  453.  
  454.   /* Deal with leading "not"'s. */
  455.   if ('!' == argv[pos][0] && '\000' == argv[pos][1])
  456.     {
  457.       value = FALSE;
  458.       while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1])
  459.     {
  460.       advance (1);
  461.       value ^= (TRUE);
  462.     }
  463.  
  464.       return (value ^ (term ()));
  465.     }
  466.  
  467.   /* A paren-bracketed argument. */  
  468.   if (argv[pos][0] == '(' && !argv[pos][1])
  469.     {
  470.       advance (1);
  471.       value = expr ();
  472.       if (argv[pos][0] != ')' || argv[pos][1])
  473.     test_syntax_error ("')' expected, found %s\n", argv[pos]);
  474.       advance (0);
  475.       return (TRUE == (value));
  476.     }
  477.  
  478.   /* are there enough arguments left that this could be dyadic? */
  479.   if (((pos + 3 <= argc) && binop (argv[pos + 1])) ||
  480.       ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2]))))
  481.     value = binary_operator ();
  482.  
  483.   /* Might be a switch type argument */
  484.   else if ('-' == argv[pos][0] && 0 == argv[pos][2])
  485.     {
  486.       if (unop (argv[pos][1]))
  487.     value = unary_operator ();
  488.       else
  489.     test_syntax_error ("%s: unary operator expected\n", argv[pos]);
  490.     }
  491.   else
  492.     {
  493.       value = (argv[pos][0] != '\0');
  494.       advance (0);
  495.     }
  496.  
  497.   return (value);
  498. }
  499.  
  500. static int
  501. binary_operator ()
  502. {
  503.   register int op;
  504.   struct stat stat_buf, stat_spare;
  505.   long int l, r, value;
  506.   /* Are the left and right integer expressions of the form '-l string'? */
  507.   int l_is_l, r_is_l;
  508.  
  509.   if (argv[pos][0] == '-' && argv[pos][1] == 'l' && !argv[pos][2])
  510.     {
  511.       l_is_l = 1;
  512.       op = pos + 2;
  513.  
  514.       /* Make sure that OP is still a valid binary operator. */
  515.       if ((op >= argc - 1) || (binop (argv[op]) == 0))
  516.     test_syntax_error ("%s: binary operator expected\n", argv[op]);
  517.  
  518.       advance (0);
  519.     }
  520.   else
  521.     {
  522.       l_is_l = 0;
  523.       op = pos + 1;
  524.     }
  525.  
  526.   if ((op < argc - 2) &&
  527.       (argv[op + 1][0] == '-' && argv[op + 1][1] == 'l' && !argv[op + 1][2]))
  528.     {
  529.       r_is_l = 1;
  530.       advance (0);
  531.     }
  532.   else
  533.     r_is_l = 0;
  534.  
  535.   if (argv[op][0] == '-')
  536.     {
  537.       /* check for eq, nt, and stuff */
  538.       switch (argv[op][1])
  539.     {
  540.     default:
  541.       break;
  542.  
  543.     case 'l':
  544.       if (argv[op][2] == 't' && !argv[op][3])
  545.         {
  546.           /* lt */
  547.           if (l_is_l)
  548.         l = strlen (argv[op - 1]);
  549.           else
  550.         {
  551.           if (!isint (argv[op - 1], &l))
  552.             integer_expected_error ("before -lt");
  553.         }
  554.  
  555.           if (r_is_l)
  556.         r = strlen (argv[op + 2]);
  557.           else
  558.         {
  559.           if (!isint (argv[op + 1], &r))
  560.             integer_expected_error ("after -lt");
  561.         }
  562.           pos += 3;
  563.           return (TRUE == (l < r));
  564.         }
  565.  
  566.       if (argv[op][2] == 'e' && !argv[op][3])
  567.         {
  568.           /* le */
  569.           if (l_is_l)
  570.         l = strlen (argv[op - 1]);
  571.           else
  572.         {
  573.           if (!isint (argv[op - 1], &l))
  574.             integer_expected_error ("before -le");
  575.         }
  576.           if (r_is_l)
  577.         r = strlen (argv[op + 2]);
  578.           else
  579.         {
  580.           if (!isint (argv[op + 1], &r))
  581.             integer_expected_error ("after -le");
  582.         }
  583.           pos += 3;
  584.           return (TRUE == (l <= r));
  585.         }
  586.       break;
  587.  
  588.     case 'g':
  589.       if (argv[op][2] == 't' && !argv[op][3])
  590.         {
  591.           /* gt integer greater than */
  592.           if (l_is_l)
  593.         l = strlen (argv[op - 1]);
  594.           else
  595.         {
  596.           if (!isint (argv[op - 1], &l))
  597.             integer_expected_error ("before -gt");
  598.         }
  599.           if (r_is_l)
  600.         r = strlen (argv[op + 2]);
  601.           else
  602.         {
  603.           if (!isint (argv[op + 1], &r))
  604.             integer_expected_error ("after -gt");
  605.         }
  606.           pos += 3;
  607.           return (TRUE == (l > r));
  608.         }
  609.  
  610.       if (argv[op][2] == 'e' && !argv[op][3])
  611.         {
  612.           /* ge - integer greater than or equal to */
  613.           if (l_is_l)
  614.         l = strlen (argv[op - 1]);
  615.           else
  616.         {
  617.           if (!isint (argv[op - 1], &l))
  618.             integer_expected_error ("before -ge");
  619.         }
  620.           if (r_is_l)
  621.         r = strlen (argv[op + 2]);
  622.           else
  623.         {
  624.           if (!isint (argv[op + 1], &r))
  625.             integer_expected_error ("after -ge");
  626.         }
  627.           pos += 3;
  628.           return (TRUE == (l >= r));
  629.         }
  630.       break;
  631.  
  632.     case 'n':
  633.       if (argv[op][2] == 't' && !argv[op][3])
  634.         {
  635.           /* nt - newer than */
  636.           pos += 3;
  637.           if (l_is_l || r_is_l)
  638.         test_syntax_error ("-nt does not accept -l\n", (char *)NULL);
  639.           if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
  640.         return (TRUE == (l > r));
  641.           else
  642.         return (FALSE);
  643.         }
  644.  
  645.       if (argv[op][2] == 'e' && !argv[op][3])
  646.         {
  647.           /* ne - integer not equal */
  648.           if (l_is_l)
  649.         l = strlen (argv[op - 1]);
  650.           else
  651.         {
  652.           if (!isint (argv[op - 1], &l))
  653.             integer_expected_error ("before -ne");
  654.         }
  655.           if (r_is_l)
  656.         r = strlen (argv[op + 2]);
  657.           else
  658.         {
  659.           if (!isint (argv[op + 1], &r))
  660.             integer_expected_error ("after -ne");
  661.         }
  662.           pos += 3;
  663.           return (TRUE == (l != r));
  664.         }
  665.       break;
  666.  
  667.     case 'e':
  668.       if (argv[op][2] == 'q' && !argv[op][3])
  669.         {
  670.           /* eq - integer equal */
  671.           if (l_is_l)
  672.         l = strlen (argv[op - 1]);
  673.           else
  674.         {
  675.           if (!isint (argv[op - 1], &l))
  676.             integer_expected_error ("before -eq");
  677.         }
  678.           if (r_is_l)
  679.         r = strlen (argv[op + 2]);
  680.           else
  681.         {
  682.           if (!isint (argv[op + 1], &r))
  683.             integer_expected_error ("after -eq");
  684.         }
  685.           pos += 3;
  686.           return (TRUE == (l == r));
  687.         }
  688.  
  689.       if (argv[op][2] == 'f' && !argv[op][3])
  690.         {
  691.           /* ef - hard link? */
  692.           pos += 3;
  693.           if (l_is_l || r_is_l)
  694.         test_syntax_error ("-ef does not accept -l\n", (char *)NULL);
  695.           if (test_stat (argv[op - 1], &stat_buf) < 0)
  696.         return (FALSE);
  697.           if (test_stat (argv[op + 1], &stat_spare) < 0)
  698.         return (FALSE);
  699.           return (TRUE ==
  700.               (stat_buf.st_dev == stat_spare.st_dev &&
  701.                stat_buf.st_ino == stat_spare.st_ino));
  702.         }
  703.       break;
  704.  
  705.     case 'o':
  706.       if ('t' == argv[op][2] && '\000' == argv[op][3])
  707.         {
  708.           /* ot - older than */
  709.           pos += 3;
  710.           if (l_is_l || r_is_l)
  711.         test_syntax_error ("-nt does not accept -l\n", (char *)NULL);
  712.           if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
  713.         return (TRUE == (l < r));
  714.           return (FALSE);
  715.         }
  716.       break;
  717.     }
  718.       test_syntax_error ("%s: unknown binary operator", argv[op]);
  719.     }
  720.  
  721.   if (argv[op][0] == '=' && !argv[op][1])
  722.     {
  723.       value = (argv[pos][0] == argv[pos+2][0]) &&
  724.           (strcmp (argv[pos], argv[pos + 2]) == 0);
  725.       pos += 3;
  726.       return (TRUE == value);
  727.     }
  728.  
  729.   if (argv[op][0] == '!' && argv[op][1] == '=' && !argv[op][2])
  730.     {
  731.       value = (argv[pos][0] != argv[pos + 2][0]) ||
  732.           (strcmp (argv[pos], argv[pos + 2]) != 0);
  733.       pos += 3;
  734.       return (TRUE == value);
  735.     }
  736.   return (FALSE);
  737. }
  738.  
  739. static int
  740. unary_operator ()
  741. {
  742.   long r, value;
  743.   struct stat stat_buf;
  744.  
  745.   switch (argv[pos][1])
  746.     {
  747.     default:
  748.       return (FALSE);
  749.  
  750.       /* All of the following unary operators use unary_advance (), which
  751.      checks to make sure that there is an argument, and then advances
  752.      pos right past it.  This means that pos - 1 is the location of the
  753.      argument. */
  754.  
  755.     case 'a':            /* file exists in the file system? */
  756.     case 'e':
  757.       unary_advance ();
  758.       value = -1 != test_stat (argv[pos - 1], &stat_buf);
  759.       return (TRUE == value);
  760.  
  761.     case 'r':            /* file is readable? */
  762.       unary_advance ();
  763.       value = -1 != EACCESS (argv[pos - 1], R_OK);
  764.       return (TRUE == value);
  765.  
  766.     case 'w':            /* File is writeable? */
  767.       unary_advance ();
  768.       value = -1 != EACCESS (argv[pos - 1], W_OK);
  769.       return (TRUE == value);
  770.  
  771.     case 'x':            /* File is executable? */
  772.       unary_advance ();
  773.       value = -1 != EACCESS (argv[pos - 1], X_OK);
  774.       return (TRUE == value);
  775.  
  776.     case 'O':            /* File is owned by you? */
  777.       unary_advance ();
  778.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  779.     return (FALSE);
  780.  
  781. #if defined (SHELL)
  782.       return (TRUE == ((UID_T) current_user.euid == (UID_T) stat_buf.st_uid));
  783. #else
  784.       return (TRUE == ((UID_T) geteuid () == (UID_T) stat_buf.st_uid));
  785. #endif /* !SHEL */
  786.  
  787.     case 'G':            /* File is owned by your group? */
  788.       unary_advance ();
  789.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  790.     return (FALSE);
  791.  
  792.       return (TRUE == ((GID_T) getegid () == (GID_T) stat_buf.st_gid));
  793.  
  794.     case 'f':            /* File is a file? */
  795.       unary_advance ();
  796.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  797.     return (FALSE);
  798.  
  799.       /* Under POSIX, -f is true if the given file exists
  800.      and is a regular file. */
  801. #if defined (S_IFMT)
  802.       return (TRUE == ((S_ISREG (stat_buf.st_mode)) ||
  803.                (0 == (stat_buf.st_mode & S_IFMT))));
  804. #else
  805.       return (TRUE == (S_ISREG (stat_buf.st_mode)));
  806. #endif /* !S_IFMT */
  807.  
  808.     case 'd':            /* File is a directory? */
  809.       unary_advance ();
  810.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  811.     return (FALSE);
  812.  
  813.       return (TRUE == (S_ISDIR (stat_buf.st_mode)));
  814.  
  815.     case 's':            /* File has something in it? */
  816.       unary_advance ();
  817.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  818.     return (FALSE);
  819.  
  820.       return (TRUE == (stat_buf.st_size > (off_t) 0));
  821.  
  822.     case 'S':            /* File is a socket? */
  823. #if !defined (S_ISSOCK)
  824.       return (FALSE);
  825. #else
  826.       unary_advance ();
  827.  
  828.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  829.     return (FALSE);
  830.  
  831.       return (TRUE == (S_ISSOCK (stat_buf.st_mode)));
  832. #endif                /* S_ISSOCK */
  833.  
  834.     case 'c':            /* File is character special? */
  835.       unary_advance ();
  836.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  837.     return (FALSE);
  838.  
  839.       return (TRUE == (S_ISCHR (stat_buf.st_mode)));
  840.  
  841.     case 'b':            /* File is block special? */
  842.       unary_advance ();
  843.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  844.     return (FALSE);
  845.  
  846.       return (TRUE == (S_ISBLK (stat_buf.st_mode)));
  847.  
  848.     case 'p':            /* File is a named pipe? */
  849.       unary_advance ();
  850. #ifndef S_ISFIFO
  851.       return (FALSE);
  852. #else
  853.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  854.     return (FALSE);
  855.       return (TRUE == (S_ISFIFO (stat_buf.st_mode)));
  856. #endif                /* S_ISFIFO */
  857.  
  858.     case 'L':            /* Same as -h  */
  859.       /*FALLTHROUGH*/
  860.  
  861.     case 'h':            /* File is a symbolic link? */
  862.       unary_advance ();
  863. #ifndef S_ISLNK
  864.       return (FALSE);
  865. #else
  866.       /* An empty filename is not a valid pathname. */
  867.       if ((argv[pos - 1][0] == '\0') ||
  868.       (lstat (argv[pos - 1], &stat_buf) < 0))
  869.     return (FALSE);
  870.  
  871.       return (TRUE == (S_ISLNK (stat_buf.st_mode)));
  872. #endif                /* S_IFLNK */
  873.  
  874.     case 'u':            /* File is setuid? */
  875.       unary_advance ();
  876.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  877.     return (FALSE);
  878.  
  879.       return (TRUE == (0 != (stat_buf.st_mode & S_ISUID)));
  880.  
  881.     case 'g':            /* File is setgid? */
  882.       unary_advance ();
  883.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  884.     return (FALSE);
  885.  
  886.       return (TRUE == (0 != (stat_buf.st_mode & S_ISGID)));
  887.  
  888.     case 'k':            /* File has sticky bit set? */
  889.       unary_advance ();
  890.       if (test_stat (argv[pos - 1], &stat_buf) < 0)
  891.     return (FALSE);
  892. #if !defined (S_ISVTX)
  893.       /* This is not Posix, and is not defined on some Posix systems. */
  894.       return (FALSE);
  895. #else
  896.       return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX)));
  897. #endif
  898.  
  899.     case 't':    /* File (fd) is a terminal?  (fd) defaults to stdout. */
  900.       advance (0);
  901.       if (pos < argc && isint (argv[pos], &r))
  902.     {
  903.       advance (0);
  904.       return (TRUE == (isatty ((int) r)));
  905.     }
  906.       return (TRUE == (isatty (1)));
  907.  
  908.     case 'n':            /* True if arg has some length. */
  909.       unary_advance ();
  910.       return (TRUE == (argv[pos - 1][0] != 0));
  911.  
  912.     case 'z':            /* True if arg has no length. */
  913.       unary_advance ();
  914.       return (TRUE == (argv[pos - 1][0] == '\0'));
  915.     }
  916. }
  917.     
  918. /*
  919.  * and:
  920.  *    term
  921.  *    term '-a' and
  922.  */
  923. static int
  924. and ()
  925. {
  926.   int value;
  927.  
  928.   value = term ();
  929.   while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2])
  930.     {
  931.       advance (0);
  932.       value = TRUTH_AND (value, and ());
  933.     }
  934.   return (TRUE == value);
  935. }
  936.  
  937. /*
  938.  * or:
  939.  *    and
  940.  *    and '-o' or
  941.  */
  942. static int
  943. or ()
  944. {
  945.   int value;
  946.  
  947.   value = and ();
  948.  
  949.   while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2])
  950.     {
  951.       advance (0);
  952.       value = TRUTH_OR (value, or ());
  953.     }
  954.  
  955.   return (TRUE == value);
  956. }
  957.  
  958. /*
  959.  * expr:
  960.  *    or
  961.  */
  962. static int
  963. expr ()
  964. {
  965.   if (pos >= argc)
  966.     beyond ();
  967.  
  968.   return (FALSE ^ (or ()));        /* Same with this. */
  969. }
  970.  
  971. /* Return TRUE if S is one of the test command's binary operators. */
  972. static int
  973. binop (s)
  974.      char *s;
  975. {
  976.   return ((STREQ (s,   "=")) || (STREQ (s,  "!=")) || (STREQ (s, "-nt")) ||
  977.       (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||
  978.       (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||
  979.       (STREQ (s, "-gt")) || (STREQ (s, "-ge")));
  980. }
  981.  
  982. /* Return non-zero if OP is one of the test command's unary operators. */
  983. static int
  984. unop (op)
  985.      int op;
  986. {
  987.   return (member (op, "abcdefgkLhprsStuwxOGnz"));
  988. }
  989.  
  990. static int
  991. two_arguments ()
  992. {
  993.   int value;
  994.  
  995.   if (argv[pos][0] == '!' && !argv[pos][1])
  996.     value = argv[pos + 1][0] == '\0';
  997.   else if ((argv[pos][0] == '-') && (argv[pos][2] == '\0'))
  998.     {
  999.       if (unop (argv[pos][1]))
  1000.     value = unary_operator ();
  1001.       else
  1002.     test_syntax_error ("%s: unary operator expected\n", argv[pos]);
  1003.     }
  1004.   else
  1005.     test_syntax_error ("%s: unary operator expected\n", argv[pos]);
  1006.  
  1007.   return (value);
  1008. }
  1009.  
  1010. static int
  1011. three_arguments ()
  1012. {
  1013.   int value;
  1014.  
  1015.   if (argv[pos][0] == '!' && !argv[pos][1])
  1016.     {
  1017.       advance (1);
  1018.       value = !two_arguments ();
  1019.     }
  1020.   else if (binop (argv[pos+1]))
  1021.     {
  1022.       value = binary_operator ();
  1023.       pos = argc;
  1024.     }
  1025.   /* Check for -a or -o or a parenthesized subexpression. */
  1026.   else if ((argv[pos+1][0] == '-' && !argv[pos+1][2] &&
  1027.           (argv[pos+1][1] == 'a' || argv[pos+1][1] == 'o')) ||
  1028.        (argv[pos][0] == '('))
  1029.     value = expr ();
  1030.   else
  1031.     test_syntax_error ("%s: binary operator expected\n", argv[pos+1]);
  1032.   return (value);
  1033. }
  1034.  
  1035. /* This is an implementation of a Posix.2 proposal by David Korn. */
  1036. static int
  1037. posixtest ()
  1038. {
  1039.   int value;
  1040.  
  1041.   switch (argc - 1)    /* one extra passed in */
  1042.     {
  1043.       case 0:
  1044.     value = FALSE;
  1045.     pos = argc;
  1046.     break;
  1047.  
  1048.       case 1:
  1049.     value = argv[1][0] != '\0';
  1050.     pos = argc;
  1051.     break;
  1052.  
  1053.       case 2:
  1054.     value = two_arguments ();
  1055.     pos = argc;
  1056.     break;
  1057.  
  1058.       case 3:
  1059.     value = three_arguments ();
  1060.     break;
  1061.  
  1062.       case 4:
  1063.     if (STREQ (argv[pos], "!"))
  1064.       {
  1065.         advance (1);
  1066.         value = !three_arguments ();
  1067.         break;
  1068.       }
  1069.     /* FALLTHROUGH */
  1070.       case 5:
  1071.       default:
  1072.     value = expr ();
  1073.     }
  1074.  
  1075.   return (value);
  1076. }
  1077.  
  1078. /*
  1079.  * [:
  1080.  *    '[' expr ']'
  1081.  * test:
  1082.  *    test expr
  1083.  */
  1084. int
  1085. #if defined (STANDALONE)
  1086. main (margc, margv)
  1087. #else
  1088. test_command (margc, margv)
  1089. #endif /* STANDALONE */
  1090.      int margc;
  1091.      char **margv;
  1092. {
  1093.   int value;
  1094.  
  1095. #if !defined (STANDALONE)
  1096.   int code;
  1097.  
  1098.   code = setjmp (test_exit_buf);
  1099.  
  1100.   if (code)
  1101.     return (test_error_return);
  1102. #endif /* STANDALONE */
  1103.  
  1104.   argv = margv;
  1105.  
  1106.   if (margv[0] && margv[0][0] == '[' && !margv[0][1])
  1107.     {
  1108.       --margc;
  1109.  
  1110.       if (margc < 2)
  1111.     test_exit (SHELL_BOOLEAN (FALSE));
  1112.  
  1113.       if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1]))
  1114.     test_syntax_error ("missing `]'\n", (char *)NULL);
  1115.     }
  1116.  
  1117.   argc = margc;
  1118.   pos = 1;
  1119.  
  1120.   if (pos >= argc)
  1121.     test_exit (SHELL_BOOLEAN (FALSE));
  1122.  
  1123.   noeval = 0;
  1124.   value = posixtest ();
  1125.  
  1126.   if (pos != argc)
  1127.     test_syntax_error ("too many arguments\n", (char *)NULL);
  1128.  
  1129.   test_exit (SHELL_BOOLEAN (value));
  1130. }
  1131.